﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDSimpleModelGenerator.Common;
using FDSimpleModelGenerator.Entities;
using FDSimpleModelGenerator.Entities.CreateTables;
using FDSimpleModelGenerator.Entities.Enums;
using FDSimpleModelGenerator.IServices;
using MySql.Data.MySqlClient;

namespace FDSimpleModelGenerator.Services.MySql
{
    /// <summary>
    /// MySql生成数据库表服务
    /// </summary>
    public class MySqlGenerateTableService : IGenerateTableService
    {
        private readonly IDbAccessor _dbAccessor;
        private readonly IDbConfigResolver _dbConfigResolver;
        public DbType DbType => DbType.MySql;

        public MySqlGenerateTableService(IDbAccessor dbAccessor, IEnumerable<IDbConfigResolver> dbConfigResolvers)
        {
            _dbAccessor = dbAccessor;
            _dbConfigResolver = dbConfigResolvers.First(r => r.DbType == DbType);
        }

        public GenResult Generate(DbConfig dbConfig, Table tableInfo)
        {
            return GenerateAsync(dbConfig, tableInfo).Result;
        }

        public async Task<GenResult> GenerateAsync(DbConfig dbConfig, Table tableInfo)
        {
            await _dbAccessor.InitAsync(() => new MySqlConnection(_dbConfigResolver.GetConnectionString(dbConfig)));

            var sb = new StringBuilder();
            sb.Append($"USE {dbConfig.Database};\r\n");
            sb.Append($"#{tableInfo.Description}\r\n");
            if (tableInfo.DeleteExists)
            {
                sb.Append($"DROP TABLE IF EXISTS `{tableInfo.Name}`;\r\n");
            }
            sb.Append($"CREATE TABLE `{tableInfo.Name}`(\r\n");
            foreach (var column in tableInfo.Columns)
            {
                sb.Append($"\t`{column.Name}`{DbDataTypeFormatter.DataType(column.DataType, column.Length, column.Precision, column.Unsigned)}{DbDataTypeFormatter.AllowNull(column.AllowNulls)}");
                sb.Append($"{DbDataTypeFormatter.Format(column.IncrementValue.ToString(), val => " AUTO_INCREMENT", val => int.TryParse(val, out int n) && n > 0, () => DbDataTypeFormatter.DefaultValue(column.DefaultValue, column.DataType))} COMMENT '{column.Remark}'");
                sb.Append(",\r\n");
            }
            var primaryKeys = tableInfo.Columns.Where(c => c.PrimaryKey).Select(c => c.Name);
            var autoIncrement = tableInfo.Columns.Max(r => r.IncrementValue);
            autoIncrement = autoIncrement < 1 ? 1 : autoIncrement;
            if (tableInfo.Indexes.Count() > 0)
            {
                foreach (var index in tableInfo.Indexes)
                {
                    var columns = index.ToIndexColumns();
                    if (columns.Count() == 0)
                    {
                        continue;
                    }

                    var type = "KEY";
                    var namePrefix = tableInfo.Name;
                    if (index.UniqueIndex)
                    {
                        type = "UNIQUE";
                        namePrefix = $"UK_{namePrefix}";
                    }

                    sb.Append(
                        $"{type} `{DbDataTypeFormatter.IndexName(namePrefix, columns).ToLower()}` {DbDataTypeFormatter.IndexColumns(columns)},\r\n"); // 使用KEY方式
                }
            }

            DbDataTypeFormatter.CheckAddPrimaryKey(sb, primaryKeys, true);

            sb.Append($") ENGINE=innoDB AUTO_INCREMENT={autoIncrement} DEFAULT CHARSET=utf8mb4 COMMENT '{tableInfo.Description}';\r\n");

            // 通用创建方式
            //if (tableInfo.Indexes.Count() > 0)
            //{
            //    sb.Append("\r\n");
            //    foreach (var index in tableInfo.Indexes)
            //    {
            //        var columns = index.ToIndexColums();
            //        if (columns.Count() == 0)
            //        {
            //            continue;
            //        }
            //        sb.Append($"CREATE INDEX {DbDataTypeFormatter.IndexName(tableInfo.Name, columns)} ON {tableInfo.Name} {DbDataTypeFormatter.IndexColumns(columns)};\r\n");
            //    }
            //}

            var result = new GenResult { Result = sb.ToString() };
            if (tableInfo.ExecuteSql)
            {
                result.IsExecuteSuccess = await _dbAccessor.ExecuteNoneQueryAsync(sb.ToString()) > 0;
            }

            return result;
        }
    }
}
